package com.imut.lagain.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.imut.lagain.entity.Notification;
import com.imut.lagain.entity.NotificationTemplate;
import com.imut.lagain.entity.User;
import com.imut.lagain.repository.NotificationRepository;
import com.imut.lagain.repository.NotificationTemplateRepository;
import com.imut.lagain.repository.UserRepository;
import com.imut.lagain.service.NotificationService;
import jakarta.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

/**
 * 通知服务实现类
 */
@Service
public class NotificationServiceImpl implements NotificationService {
    private static final Logger log = LoggerFactory.getLogger(NotificationServiceImpl.class);

    @Autowired
    private NotificationRepository notificationRepository;

    @Autowired
    private NotificationTemplateRepository templateRepository;

    @Autowired
    private UserRepository userRepository;

    @Resource
    private com.imut.lagain.service.IWechatNotificationService wechatNotificationService;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    private static final String FREQUENCY_LIMIT_KEY = "notification:frequency:";
    private static final String UNREAD_COUNT_KEY = "notification:unread:";

    @Override
    @Transactional
    public Notification createNotification(Notification notification, Long currentUserId) {
        try {
            notification.setUserId(currentUserId);
            notification.setStatus(Notification.NotificationStatus.PENDING);
            notification.setCreatedAt(LocalDateTime.now());
            notification.setUpdatedAt(LocalDateTime.now());
            
            notificationRepository.insert(notification);
            Notification saved = notificationRepository.selectById(notification.getId());
            updateUnreadCountCache(currentUserId);
            
            log.info("创建通知成功，ID: {}, 用户: {}, 类型: {}", saved.getId(), currentUserId, notification.getType());
            return saved;
        } catch (Exception e) {
            log.error("创建通知失败", e);
            throw new RuntimeException("创建通知失败", e);
        }
    }

    @Transactional
    @Override
    public boolean createNotification(Notification notification) {
        try {
            NotificationTemplate template = templateRepository.findByCodeAndEnabled(notification.getTemplateCode(), true);
            if (template == null) {
                log.error("通知模板不存在或未启用: {}", notification.getTemplateCode());
                return false;
            }

            notification.setType(template.getType());
            notification.setTitle(renderTemplate(template.getTitle(), notification.getData()));
            notification.setContent(renderTemplate(template.getContent(), notification.getData()));
            notification.setExtraData(notification.getData());
            notification.setStatus(Notification.NotificationStatus.PENDING);
            notification.setPriority(1);
            notification.setIsDeleted(false);
            notification.setCreatedAt(LocalDateTime.now());
            notification.setUpdatedAt(LocalDateTime.now());

            notificationRepository.insert(notification);
            Notification saved = notificationRepository.selectById(notification.getId());
            
            log.info("更新未读数量缓存");
            updateUnreadCountCache(notification.getUserId());
            
            log.info("创建通知成功，ID: {}, 用户: {}, 类型: {}", saved.getId(), notification.getUserId(), notification.getType());
            return true;
        } catch (Exception e) {
            log.error("创建通知失败", e);
            throw new RuntimeException("创建通知失败", e);
        }
    }

    @Override
    @Transactional
    public Notification createNotification(Long userId, Notification.NotificationType type, String title, String content, Map<String, Object> data) {
        try {
            Notification notification = new Notification();
            notification.setUserId(userId);
            notification.setType(type);
            notification.setTitle(title);
            notification.setContent(content);
            notification.setExtraData(data);
            notification.setStatus(Notification.NotificationStatus.PENDING);
            notification.setPriority(1);
            notification.setIsDeleted(false);
            notification.setCreatedAt(LocalDateTime.now());
            notification.setUpdatedAt(LocalDateTime.now());

            notificationRepository.insert(notification);
            Notification saved = notificationRepository.selectById(notification.getId());
            
            log.info("更新未读数量缓存");
            updateUnreadCountCache(userId);
            
            log.info("创建通知成功，ID: {}, 用户: {}, 类型: {}", saved.getId(), userId, type);
            return saved;
        } catch (Exception e) {
            log.error("创建通知失败", e);
            throw new RuntimeException("创建通知失败", e);
        }
    }

    @Override
    @Transactional
    public boolean sendSystemNotification(String templateCode, Map<String, Object> data, List<Long> userIds) {
        try {
            NotificationTemplate template = templateRepository.findByCodeAndEnabled(templateCode, true);
            if (template == null) {
                throw new RuntimeException("模板不存在或未启用: " + templateCode);
            }

            for (Long userId : userIds) {
                log.info("检查发送频率限制");
                if (!checkFrequencyLimit(userId, template)) {
                    log.warn("用户 {} 触发频率限制，跳过发送模板 {}", userId, templateCode);
                    continue;
                }

                log.info("创建通知");
                Notification notification = createNotification(
                    userId, 
                    template.getType(), 
                    renderTemplate(template.getTitle(), data),
                    renderTemplate(template.getContent(), data),
                    data
                );

                log.info("设置模板相关信息");
                notification.setTemplateId(template.getId());
                notification.setJumpUrl(renderTemplate(template.getUrl(), data));
                notification.setExpireAt(template.getExpireHours() != null ? 
                    LocalDateTime.now().plusHours(template.getExpireHours()) : null);
                notification.setPriority(template.getPriority());

                notificationRepository.insert(notification);

                log.info("发送微信通知");
                if (template.getWechatTemplateId() != null && !template.getWechatTemplateId().isEmpty()) {
                    sendWechatNotification(notification, template, data);
                }

                log.info("记录发送频率");
                recordFrequency(userId, template);
            }

            log.info("系统通知发送完成，模板: {}, 用户数: {}", templateCode, userIds.size());
            return true;
        } catch (Exception e) {
            log.error("发送系统通知失败", e);
            return false;
        }
    }

    @Override
    @Transactional
    public boolean sendUserNotification(Long fromUserId, Long toUserId, String templateCode, Map<String, Object> data) {
        try {
            NotificationTemplate template = templateRepository.findByCodeAndEnabled(templateCode, true);
            if (template == null) {
                throw new RuntimeException("模板不存在或未启用: " + templateCode);
            }

            log.info("检查发送条件");
            if (!checkSendCondition(template, data)) {
                log.warn("发送条件不满足，跳过发送: {}", templateCode);
                return false;
            }

            log.info("检查频率限制");
            if (!checkFrequencyLimit(toUserId, template)) {
                log.warn("用户 {} 触发频率限制，跳过发送模板 {}", toUserId, templateCode);
                return false;
            }

            log.info("添加发送者信息到数据中");
            if (fromUserId != null) {
                User fromUser = userRepository.selectById(fromUserId);
                if (fromUser != null) {
                    data.put("fromUserName", fromUser.getNickname());
                    data.put("fromUserAvatar", fromUser.getAvatarUrl());
                }
            }

            log.info("创建通知");
            Notification notification = createNotification(
                toUserId,
                template.getType(),
                renderTemplate(template.getTitle(), data),
                renderTemplate(template.getContent(), data),
                data
            );

            notification.setFromUserId(fromUserId);
            notification.setTemplateId(template.getId());
            notification.setJumpUrl(renderTemplate(template.getUrl(), data));
            notification.setExpireAt(template.getExpireHours() != null ? 
                LocalDateTime.now().plusHours(template.getExpireHours()) : null);
            notification.setPriority(template.getPriority());

            notificationRepository.insert(notification);

            log.info("发送微信通知");
            if (template.getWechatTemplateId() != null && !template.getWechatTemplateId().isEmpty()) {
                sendWechatNotification(notification, template, data);
            }

            log.info("记录发送频率");
            recordFrequency(toUserId, template);

            log.info("用户通知发送成功，从用户: {} 到用户: {}, 模板: {}", fromUserId, toUserId, templateCode);
            return true;
        } catch (Exception e) {
            log.error("发送用户通知失败", e);
            return false;
        }
    }

    @Override
    @Transactional
    public boolean sendReminderNotification(Long userId, String templateCode, Map<String, Object> data, LocalDateTime scheduleTime) {
        try {
            NotificationTemplate template = templateRepository.findByCodeAndEnabled(templateCode, true);
            if (template == null) {
                throw new RuntimeException("模板不存在或未启用: " + templateCode);
            }

            log.info("检查发送条件");
            if (!checkSendCondition(template, data)) {
                log.warn("发送条件不满足，跳过发送: {}", templateCode);
                return false;
            }

            log.info("检查频率限制");
            if (!checkFrequencyLimit(userId, template)) {
                log.warn("用户 {} 触发频率限制，跳过发送模板 {}", userId, templateCode);
                return false;
            }

            log.info("创建提醒通知");
            Notification notification = createNotification(
                userId,
                template.getType(),
                renderTemplate(template.getTitle(), data),
                renderTemplate(template.getContent(), data),
                data
            );

            notification.setTemplateId(template.getId());
            notification.setJumpUrl(renderTemplate(template.getUrl(), data));
            notification.setExpireAt(template.getExpireHours() != null ? 
                LocalDateTime.now().plusHours(template.getExpireHours()) : null);
            notification.setPriority(template.getPriority());
            notification.setScheduleTime(scheduleTime);

            notificationRepository.updateById(notification);

            log.info("发送微信通知");
            if (template.getWechatTemplateId() != null && !template.getWechatTemplateId().isEmpty()) {
                sendWechatNotification(notification, template, data);
            }

            log.info("记录发送频率");
            recordFrequency(userId, template);

            log.info("提醒通知发送成功，用户: {}, 模板: {}, 计划时间: {}", userId, templateCode, scheduleTime);
            return true;
        } catch (Exception e) {
            log.error("发送提醒通知失败", e);
            return false;
        }
    }

    @Override
    public IPage<Notification> getNotificationsByUser(Long userId, int page, int size, Notification.NotificationType type, Boolean isRead) {
        try {
            Page<Notification> pageRequest = new Page<>(page, size);
            QueryWrapper<Notification> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("user_id", userId)
                       .eq("is_deleted", false)
                       .orderByDesc("created_at");

            if (type != null) {
                queryWrapper.eq("type", type);
            }

            if (isRead != null) {
                queryWrapper.eq("is_read", isRead);
            }

            return notificationRepository.selectPage(pageRequest, queryWrapper);
        } catch (Exception e) {
            log.error("查询用户通知列表失败", e);
            return new Page<>();
        }
    }

    @Override
    public Notification getNotificationById(Long id) {
        try {
            return notificationRepository.selectById(id);
        } catch (Exception e) {
            log.error("获取通知失败", e);
            return null;
        }
    }

    @Override
    @Transactional
    public boolean markAsRead(Long notificationId, Long userId) {
        try {
            Optional<Notification> optionalNotification = notificationRepository.findById(notificationId);
            if (optionalNotification.isEmpty()) {
                return false;
            }

            Notification notification = optionalNotification.get();
            if (!notification.getUserId().equals(userId)) {
                return false;
            }

            if (!notification.getIsRead()) {
                notification.setIsRead(true);
                notification.setReadAt(LocalDateTime.now());
                notification.setUpdatedAt(LocalDateTime.now());
                notificationRepository.updateById(notification);

                log.info("更新未读数量缓存");
                updateUnreadCountCache(userId);
            }

            return true;
        } catch (Exception e) {
            log.error("标记通知已读失败", e);
            return false;
        }
    }

    @Override
    @Transactional
    public boolean deleteNotification(Long notificationId, Long userId) {
        try {
            Optional<Notification> optionalNotification = notificationRepository.findById(notificationId);
            if (optionalNotification.isEmpty()) {
                return false;
            }

            Notification notification = optionalNotification.get();
            if (!notification.getUserId().equals(userId)) {
                return false;
            }

            notification.setIsDeleted(true);
            notification.setUpdatedAt(LocalDateTime.now());
            notificationRepository.updateById(notification);

            log.info("如果是未读通知，更新未读数量缓存");
            if (!notification.getIsRead()) {
                updateUnreadCountCache(userId);
            }

            return true;
        } catch (Exception e) {
            log.error("删除通知失败", e);
            return false;
        }
    }

    @Override
    public Optional<Notification> getNotificationDetail(Long notificationId, Long userId) {
        try {
            Optional<Notification> notification = notificationRepository.findById(notificationId);
            if (notification.isPresent() && notification.get().getUserId().equals(userId)) {
                return notification;
            }
            return Optional.empty();
        } catch (Exception e) {
            log.error("获取通知详情失败", e);
            return Optional.empty();
        }
    }

    @Override
    public long getUnreadCount(Long userId) {
        try {
            String cacheKey = UNREAD_COUNT_KEY + userId;
            Object cached = redisTemplate.opsForValue().get(cacheKey);
            if (cached != null) {
                return Long.parseLong(cached.toString());
            }

            QueryWrapper<Notification> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("user_id", userId)
                       .eq("is_read", false)
                       .eq("is_deleted", false);

            long count = notificationRepository.selectCount(queryWrapper);
            redisTemplate.opsForValue().set(cacheKey, count, 1, TimeUnit.HOURS);
            return count;
        } catch (Exception e) {
            log.error("查询未读通知数量失败", e);
            return 0;
        }
    }

    @Override
    @Transactional
    public boolean markAllAsRead(Long userId) {
        try {
            QueryWrapper<Notification> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("user_id", userId)
                       .eq("is_read", false)
                       .eq("is_deleted", false);

            List<Notification> unreadNotifications = notificationRepository.selectList(queryWrapper);
            if (unreadNotifications.isEmpty()) {
                return true;
            }

            LocalDateTime now = LocalDateTime.now();
            for (Notification notification : unreadNotifications) {
                notification.setIsRead(true);
                notification.setReadAt(now);
                notification.setUpdatedAt(now);
            }

            notificationRepository.updateBatch(unreadNotifications);
            updateUnreadCountCache(userId);

            log.info("批量标记已读成功，用户: {}, 数量: {}", userId, unreadNotifications.size());
            return true;
        } catch (Exception e) {
            log.error("批量标记已读失败", e);
            return false;
        }
    }

    @Override
    @Transactional
    public void cleanExpiredNotifications() {
        try {
            cleanupExpiredReadNotifications();
            log.info("清理过期通知完成");
        } catch (Exception e) {
            log.error("清理过期通知失败", e);
        }
    }

    @Override
    @Transactional
    public void cleanupExpiredNotifications() {
        cleanExpiredNotifications();
    }

    @Override
    @Transactional
    public int retryFailedWechatNotifications() {
        try {
            // 查找微信发送失败的通知
            QueryWrapper<Notification> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("wechat_sent", false)
                       .isNotNull("wechat_sent_at")
                       .gt("created_at", LocalDateTime.now().minusDays(1)); // 只重试1天内的

            List<Notification> failedNotifications = notificationRepository.selectList(queryWrapper);
            int retryCount = 0;

            for (Notification notification : failedNotifications) {
                try {
                    // 获取模板信息
                    NotificationTemplate template = templateRepository.selectById(notification.getTemplateId());
                    if (template != null && template.getWechatTemplateId() != null) {
                        // 重新发送微信通知
                        Map<String, Object> data = notification.getData() != null ? notification.getData() : new HashMap<>();
                        sendWechatNotification(notification, template, data);
                        retryCount++;
                    }
                } catch (Exception e) {
                    log.error("重试微信通知失败，通知ID: {}", notification.getId(), e);
                }
            }

            log.info("重试失败的微信通知完成，重试数量: {}", retryCount);
            return retryCount;
        } catch (Exception e) {
            log.error("重试失败的微信通知失败", e);
            return 0;
        }
    }

    private void cleanupExpiredReadNotifications() {
        try {
            LocalDateTime expireTime = LocalDateTime.now().minusDays(30);
            QueryWrapper<Notification> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("is_read", true)
                       .lt("read_at", expireTime);

            List<Notification> expiredNotifications = notificationRepository.selectList(queryWrapper);
            if (!expiredNotifications.isEmpty()) {
                // 批量更新状态
                notificationRepository.updateBatch(expiredNotifications);
                log.info("批量更新通知状态完成，数量: {}", expiredNotifications.size());
            }
        } catch (Exception e) {
            log.error("清理过期已读通知失败", e);
        }
    }

    private void sendWechatNotification(Notification notification, NotificationTemplate template, Map<String, Object> data) {
        try {
            if (wechatNotificationService != null) {
                // 构造Notification对象
                Notification notificationObj = new Notification();
                notificationObj.setUserId(notification.getUserId());
                notificationObj.setJumpUrl(notification.getJumpUrl());
                
                boolean success = wechatNotificationService.sendTemplateMessage(
                    notificationObj,
                    template,
                    data
                );
                
                notification.setWechatSent(success);
                notification.setWechatSentAt(LocalDateTime.now());
                notificationRepository.updateById(notification);
            }
        } catch (Exception e) {
            log.error("发送微信通知失败", e);
            notification.setWechatSent(false);
            notification.setWechatSentAt(LocalDateTime.now());
            notificationRepository.updateById(notification);
        }
    }

    private String renderTemplate(String template, Map<String, Object> data) {
        if (template == null || data == null) {
            return template;
        }
        
        String result = template;
        for (Map.Entry<String, Object> entry : data.entrySet()) {
            String placeholder = "${" + entry.getKey() + "}";
            String value = entry.getValue() != null ? entry.getValue().toString() : "";
            result = result.replace(placeholder, value);
        }
        
        return result;
    }

    private boolean checkFrequencyLimit(Long userId, NotificationTemplate template) {
        if (template.getFrequencyLimit() == null || template.getFrequencyLimit() <= 0) {
            return true;
        }

        try {
            String key = FREQUENCY_LIMIT_KEY + userId + ":" + template.getCode();
            String count = (String) redisTemplate.opsForValue().get(key);
            
            if (count == null) {
                return true;
            }
            
            return Integer.parseInt(count) < template.getFrequencyLimit();
        } catch (Exception e) {
            log.error("检查频率限制失败", e);
            return true;
        }
    }

    private void recordFrequency(Long userId, NotificationTemplate template) {
        if (template.getFrequencyLimit() == null || template.getFrequencyLimit() <= 0) {
            return;
        }

        try {
            String key = FREQUENCY_LIMIT_KEY + userId + ":" + template.getCode();
            redisTemplate.opsForValue().increment(key);
            redisTemplate.expire(key, 24, TimeUnit.HOURS);
        } catch (Exception e) {
            log.error("记录发送频率失败", e);
        }
    }

    private boolean checkSendCondition(NotificationTemplate template, Map<String, Object> data) {
        if (template.getSendCondition() == null || template.getSendCondition().isEmpty()) {
            return true;
        }
        
        return true;
    }

    private void updateUnreadCountCache(Long userId) {
        try {
            String cacheKey = UNREAD_COUNT_KEY + userId;
            redisTemplate.delete(cacheKey);
        } catch (Exception e) {
            log.error("更新未读数量缓存失败", e);
        }
    }
}